"""
ceph-mgr Output Wizards module

Output wizards are used to process results in different ways in
completion objects
"""

import json
import logging

from ceph.deployment import inventory
from orchestrator import InventoryNode

from .ansible_runner_svc import EVENT_DATA_URL

logger = logging.getLogger(__name__)

class OutputWizard(object):
    """Base class for help to process output in completion objects
    """
    def __init__(self, ar_client):
        """Make easy to work in output wizards using this attributes:

        :param ars_client: Ansible Runner Service client
        """
        self.ar_client = ar_client

    def process(self, operation_id, raw_result):
        """Make the magic here

        :param operation_id: Allows to identify the Ansible Runner Service
                             operation whose result we wnat to process
        :param raw_result: input for processing
        """
        raise NotImplementedError

class ProcessInventory(OutputWizard):
    """ Adapt the output of the playbook used in 'get_inventory'
        to the Orchestrator expected output (list of InventoryNode)
    """

    def process(self, operation_id, raw_result):
        """
        :param operation_id: Playbook uuid
        :param raw_result: events dict with the results

            Example:
            inventory_events =
            {'37-100564f1-9fed-48c2-bd62-4ae8636dfcdb': {'host': '192.168.121.254',
                                                        'task': 'list storage inventory',
                                                        'event': 'runner_on_ok'},
            '36-2016b900-e38f-7dcd-a2e7-00000000000e': {'host': '192.168.121.252'
                                                        'task': 'list storage inventory',
                                                        'event': 'runner_on_ok'}}

        :return              : list of InventoryNode
        """
        # Just making more readable the method
        inventory_events = raw_result

        #Obtain the needed data for each result event
        inventory_nodes = []

        # Loop over the result events and request the event data
        for event_key, dummy_data in inventory_events.items():

            event_response = self.ar_client.http_get(EVENT_DATA_URL %
                                                     (operation_id, event_key))

            # self.pb_execution.play_uuid

            # Process the data for each event
            if event_response:
                event_data = json.loads(event_response.text)["data"]["event_data"]

                host = event_data["host"]

                devices = json.loads(event_data["res"]["stdout"])
                devs = inventory.Devices.from_json(devices)
                inventory_nodes.append(InventoryNode(host, devs))


        return inventory_nodes

class ProcessPlaybookResult(OutputWizard):
    """ Provides the result of a playbook execution as plain text
    """
    def process(self, operation_id, raw_result):
        """
        :param operation_id: Playbook uuid
        :param raw_result: events dict with the results

        :return              : String with the playbook execution event list
        """
        # Just making more readable the method
        inventory_events = raw_result
        result = ""

        # Loop over the result events and request the data
        for event_key, dummy_data in inventory_events.items():
            event_response = self.ar_client.http_get(EVENT_DATA_URL %
                                                     (operation_id, event_key))

            result += event_response.text
        return result


class ProcessHostsList(OutputWizard):
    """ Format the output of host ls call
    """
    def process(self, operation_id, raw_result):
        """ Format the output of host ls call

        :param operation_id: Not used in this output wizard
        :param raw_result: In this case is like the following json:
                {
                "status": "OK",
                "msg": "",
                "data": {
                    "hosts": [
                        "host_a",
                        "host_b",
                        ...
                        "host_x",
                        ]
                    }
                }

        :return: list of InventoryNodes
        """
        # Just making more readable the method
        host_ls_json = raw_result

        inventory_nodes = []

        try:
            json_resp = json.loads(host_ls_json)

            for host in json_resp["data"]["hosts"]:
                inventory_nodes.append(InventoryNode(host, inventory.Devices([])))

        except ValueError:
            logger.exception("Malformed json response")
        except KeyError:
            logger.exception("Unexpected content in Ansible Runner Service"
                               " response")
        except TypeError:
            logger.exception("Hosts data must be iterable in Ansible Runner "
                               "Service response")

        return inventory_nodes
